package main

import (
	"fmt"
	"net/http"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

var config = make(map[string]map[string]map[string]string)

func init() {
	//"http://httpbin.org/post"
	config["send_bonus"] = make(map[string]map[string]string, 0)
	/*	config["send_bonus"]["test1.com"]=make(map[string]string)
		config["send_bonus"]["test1.com"]["speed"]="100"
		config["send_bonus"]["test1.com"]["retry"]="2"*/

	config["send_bonus"]["http://httpbin.org/post"] = make(map[string]string)
	config["send_bonus"]["http://httpbin.org/post"]["speed"] = "100"
	config["send_bonus"]["http://httpbin.org/post"]["retry"] = "3"
}

/*
var config=[
    "send_bonus":[
        "test1.com":[
            "speed":100,
            "retry":2
        ],
        "test2.com":[
            "speed":80,
            "speed":3
        ],
    ]
]
*/
var waitGroup = sync.WaitGroup{}
var waitGroup1 = sync.WaitGroup{}
var chanList = make(map[string]chan int)

//测试请求限制
func main() {
	fmt.Println(config)
	for msg_type, conf := range config {
		fmt.Println(msg_type)
		for server, server_conf := range conf {
			fmt.Println(server, "\n", server_conf)
			waitGroup.Add(1)
			chan_name := fmt.Sprintf("%S%S", msg_type, server)
			chan_len, err := strconv.Atoi(server_conf["speed"])
			if err != nil {
				fmt.Println(fmt.Sprintf("消息类型[%s]下[%s]服务的最大连接数[speed]配置错误", msg_type, server), server_conf)
				os.Exit(1)
			}
			chanList[chan_name] = make(chan int, chan_len)
			go sendMsg(server, msg_type, server_conf, chanList[chan_name])
		}
	}
	//time.Sleep(time.Second)
	waitGroup.Wait()
}

//限制并发2 每秒计数满最大消费后睡眠 【 1秒-开辟子协程的耗时 】
func sendMsg(url, msg_type string, server_conf map[string]string, msg_server_chan chan int) {
	speed, _ := strconv.Atoi(server_conf["speed"]) //限制最大并发
	try_num, _ := strconv.Atoi(server_conf["retry"])

	start_time := time.Now()
	for i := 0; i < 1; i++ {
		redis := redis2{}
		data := redis.get(1000)
		if len(data) == 0 { //没有数据时睡眠一秒
			fmt.Println("没有数据睡一秒")
			time.Sleep(time.Second)
			fmt.Println("结束睡眠")
		}
		um := time.Second.Nanoseconds()
		inc := 0
		now_time := time.Now().UnixNano()
		for _, msg := range data {
			refresh_time := time.Now().UnixNano()
			if msg["type"] == msg_type {

				if inc < speed {
					inc++
				} else {
					spend_time := refresh_time - now_time
					if um > spend_time { // 消费一定数量的耗时超过 1 秒 就不用睡眠，直接重置计数器和起始时间
						time.Sleep(time.Duration(um - spend_time))
					}
					inc = 0
					now_time = time.Now().UnixNano()
					fmt.Println(now_time)
				}
				waitGroup1.Add(1)
				msg_server_chan <- inc
				go doPost(url, msg["msg"], try_num, msg_server_chan)
			}
		}
	}
	waitGroup1.Wait()
	end_time := time.Now()
	fmt.Println(start_time.Second(), end_time.Second())
	waitGroup.Done()

	for i := 0; i <= 10; {
		go push()
	}
}

func push() {
	for {
		//channel取
		//pusher()
		fmt.Println("aaa")
	}
}

func doPost(url, msg string, retry int, msg_server_chan chan int) {
	try_num := 0
Retry:
	_, err := http.Post(url, "application/x-www-form-urlencoded", strings.NewReader("msg="+msg))
	if err != nil {
		fmt.Println(url, "第", try_num+1, "次尝试失败")
		if try_num < retry || retry == -1 { // retry=-1时无限重试
			try_num++
			goto Retry //错误重试
		}
		// 重试多次任然失败后记录日志，人工处理
		fmt.Println(url, try_num, "次尝试失败，转人工处理，消息内容：", msg)
	} else {
		//fmt.Println(url,"消息发送成功，消息内容：",msg)
	}
	waitGroup1.Done()
	<-msg_server_chan
	//err 重试
}

type redis2 struct {
	inc int
}

func (r *redis2) get(lenght int) (data []map[string]string) {

	if r.inc < 2 {
		for i := 0; i < lenght; i++ {
			mp := make(map[string]string)
			mp["type"] = "send_bonus"
			mp["msg"] = "发红包···" + strconv.Itoa(i)
			data = append(data, mp)
		}
	}
	r.inc++
	return
}
